use16            ;primero se utiliza codigo de 16 bits

ORG 0x7C00

	jmp continuar
	nop

;Informacion de la FAT12
Nombre         db 'EL POS  '
BytesPorSect   dw 200h
SectPorCluster db 1
SectReservados dw 1
NumFATs        db 2
EntrDirRaiz    dw 0E0h
TotSect16      dw 0B40h
Media          db 0F0h
TamFAT         dw 9
SectPorPista   dw 18
NumCab         dw 2
SectOcultos    dd 0
TotSect32      dd 0
DriveNum       db 0
Reservado1     db 0
FirmaBoot      db 029h
IDVol          dd 11223344h
EtiqVol        db 'EL POS     '
TipoSistArch   db 'FAT12   '

continuar:
	mov ax, 0B800h    ; limpiar pantalla
	mov es, ax
	xor di, di
	mov ax, 0700h
	mov cx, 0FA0h     ; 80*25*2
	rep stosw

	mov ah, 2        ;cambiar posicion del cursos a 0,0
	xor bh, bh
	xor dx, dx
	int 10h

	mov ax, 8000h
	mov es, ax
	xor bx, bx              ; cargar sector en ES:BX 8000h:0000h

	call reset_drive

	mov ax, 18              ; LBA del directorio raiz
	                        ; SectReservados+(NumFATs*TamFAT)-2
	                        ; El -2 es porque en el ciclo se incremente este valor
	; leer directorio raiz, sectores a leer=EntrDirRaiz*32/512
	mov cx, [EntrDirRaiz]
	shl cx, 5               ; EntrDirRaiz*32=TotBytes
	shr cx, 9               ; TotBytes/512=TotSectores
	                        ; cx = contador de sectores a leer
ciclo_fat:
	inc ax
	push ax                 ; guardar LBA
	push bx                 ; guardar el apuntador a la direcc destino
	push cx                 ; guardar contador

	call LBACHS
	mov ah, 02h             ; leer sector
	mov al, 1               ; numero de sectores a leer
	int 13h

	or ah, ah               ; verificar resultado
	jz rev_entrada
	call reset_drive        ; error si ah <> 0

rev_entrada:
	; recorrer directorio raiz para buscar archivo KERNEL.BIN
	; Los datos del directorio raiz estan en 8000h:0000h
	mov cx, 16h            ; contador = entradas del directorio por sector
	                       ; 512/32=16
	xor di, di             ; ES:DI = 8000h:0000h

	lea si, [ArchKernel]   ; DS:SI = variable que contiene el nombre del archivo

rev_entrada2:
	mov al, [ES:DI]        ; verificar si es la ultima entrada
	or al, al
	jz error_ArchNoEncontrado

	;mov al, [ES:DI]        ; verificar si la entrada de directorio es utilizada
	cmp al, 0E5h
	je sig_entrada

	mov al, [ES:DI + 0Bh]  ; verificar si es nombre largo
	xor al, 0Fh
	jz sig_entrada

	push cx
	mov cx, 11
	rep cmpsb	
	pop cx
	je KernelEncontrado

sig_entrada:
	sub cx, 1                 ; decrementar contador
	jz ciclo_fat2             ; si contador=0, ya se acabaron las entradas
	add di, 20h               ; aumentar apuntador a la siguiente entrada
	jmp rev_entrada2

ciclo_fat2:
	pop cx
	pop bx
	pop ax

	xor bx, bx              ; cargar sector en ES:BX 8000h:0000h
	sub cx, 1               ; decrementar contador
	jnz ciclo_fat	
	jmp error_ArchNoEncontrado

KernelEncontrado:
	; leer FAT en 8000h:0000h
	add di, 0Fh              ; mover DI a la direcc del primer cluster
	mov ax, [ES:DI]          ; ax = cluster inicial
	push ax                  ; guardar num cluster

	xor bx, bx
	mov cx, 9            ; total de sectores de la FAT (TamFAT)
	xor ax, ax
leerFAT:
	push cx
	add ax, 1
	call LBACHS
	mov ax, 0201h
	int 13h
	pop cx
	add bx, 200h
	sub cx, 1
	jz leerKernel
	jmp leerFAT
leerKernel:
	pop ax                   ; recuperar num cluster
	xor bx, bx
	mov es, bx
	mov bx, 1000h            ; ES:BX = 0000h:1000h buffer para guardar kernel
	push ds
	push 8000h               ; valor para asignar a DS, para recuperar sig cluster
leerKernel2:
	push ax                  ; guardar num. de cluster
	sub ax, 2                ; LBA = ((cluster-2)*SectPorCluster) + primer sector de datos
	add ax, 21h              ; PSD=SectReservados+(NumFATs+TamFAT)+SectDirRaiz
	call LBACHS
	mov ax, 0201h
	int 13h
	add bx, 200h

	pop cx                  ; recuperar num. de cluster
	mov ax, cx
	shl ax, 1               ; sig sector en FAT cluster*(3/2)
	add ax, cx
	shr ax, 1
	mov si, ax
	pop ds                  ; DS = 8000h
	lodsw                   ; Sig cluster del archivo
	pop ds
	push ds
	push 8000h
	clc
	shr cx, 1
	jc impar
	and ax, 0FFFh
	jmp finKernel
impar:
	and ax, 0FFF0h
	shr ax, 4
finKernel:
	cmp ax, 0FFFh          ; Si AX=FFFh, final de lista de clusters
	je finKernel2
	jmp leerKernel2
finKernel2:
	pop ds
	pop ds
	jmp continuarKernel

error_ArchNoEncontrado:
	lea si, [msgArchNoEncontrado]
	call imprimirCadena
	hlt

; input: DS:SI, direccion de la cadena
imprimirCadena:
	cld
	xor di, di

sig_char:
	lodsb
	or al, al
	jz fin
	mov ah, 0Eh
	mov bx, 7
	int 10h
	jmp sig_char
fin:
	ret

reset_drive:
	mov ah, 0               ; comando RESET
	int 13h
	or ah, ah               ; Resultado se regresa en AH
	jnz reset_drive         ; Intentar de nuevo si hubo error
	ret
 
LBACHS:
	; Input: ax - LBA
	; Output: ax - sector, bx - cabeza, cx - cilindro

	push bx
	push dx

	xor dx,dx
	mov bx,[SectPorPista] ;Sectores por pista
	div bx           ; dividir ax/bx, resul ax=cociente, dx=residuo
	inc dx
	push dx			 ; guardar sector
	
	xor dx,dx
	mov bx,[NumCab]  ; Numero de cabezas
	div bx			 ; ax=cociente de la operacion anterior
                     ; dividir ax/bx, ax=cociente, dx=residuo

	mov ch,al       ; cilindro
	mov bh,dl       ; cabeza, movimiento temporal, despues se pone en dh
	pop ax          ; recuperar sector
	mov cl, al      ; guardar sector

	pop dx
	mov dh, bh
	pop bx
	
	ret

continuarKernel:
	cli                     ; Inhabilitar interrupciones
	
	xor ax, ax
	mov ds, ax              ; Set DS-register to 0 - used by lgdt
	
	lgdt [gdt_desc]         ; Load the GDT descriptor
	
	mov eax, cr0            ; Copy the contents of CR0 into EAX
	or eax, 1               ; Set bit 0
	mov cr0, eax            ; Copy the contents of EAX into CR0
	
	jmp 08h:clear_pipe      ; Jump to code segment, offset clear_pipe

use32                       ; Ahora se utiliza codigo de 32 bits (modo protegido)
clear_pipe:
	mov ax, 10h             ; Save data segment identifyer
	mov ds, ax              ; Move a valid data segment into the data segment register
	mov ss, ax              ; Move a valid data segment into the stack segment register
	mov esp, 090000h        ; Move the stack pointer to 090000h

	jmp 08h:01000h          ; Jump to section 08h (code), offset 01000h

gdt:                    ; Address for the GDT
gdt_null:               ; Null Segment
	dd 0
	dd 0

gdt_code:               ; Code segment, read/execute, nonconforming
	dw 0FFFFh
	dw 0
	db 0
	db 10011010b
	db 11001111b
	db 0

gdt_data:               ; Data segment, read/write, expand down
	dw 0FFFFh
	dw 0
	db 0
	db 10010010b
	db 11001111b
	db 0

gdt_end:                ; Used to calculate the size of the GDT

gdt_desc:                   ; The GDT descriptor
	dw gdt_end - gdt - 1    ; Limit (size)
	dd gdt                  ; Address of the GDT

msgArchNoEncontrado db 'ERROR, no se encontro el archivo KERNEL.BIN',13,10,0
ArchKernel db 'KERNEL  BIN'

times 510-($-$$) db 0       ; rellenar hasta completar 512 bytes
	dw 0AA55h
